package com.ruoyi.config;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.domain.WsResult;
import com.ruoyi.enums.ConnectDeviceTypeEnum;
import com.ruoyi.enums.WsCode;
import com.ruoyi.enums.WsType;
import com.ruoyi.util.RedisManager;
import com.ruoyi.util.TokenParseUtil;
import com.ruoyi.util.WsResultEncoder;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import static org.apache.commons.collections4.MapUtils.getString;

/**
 *
 * WebSocket服务端连接
 *
 * @author xkliu
 */
@Slf4j
@Component
@ServerEndpoint(value = "/websocket",encoders = {WsResultEncoder.class})
public class WebSocket {

    private static final String PING = "ping";

    /**
     *  与某个客户端的连接对话，需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     *  设备平台类型
     */
    private String type;

    private String userName;

    /**
     * 标识当前连接客户端的用户名
     */
    private Long userId;

    static WebSocketManager webSocketManager = WebSocketManager.INSTANCE;

    @OnOpen
    public void onOpen(Session session){
        Map<String, List<String>> parameterMap = session.getRequestParameterMap();
        String authorization = getString(parameterMap, "Authorization");
        String deviceType = getString(parameterMap, "deviceType");
        if (authorization.isEmpty()){
            errorMessage("token为空" , session);
            return;
        }
        //由于authorization取出来有[],将去掉，待后续和前端对接测试
        authorization = authorization.substring(1, authorization.length()-1);
        Claims claims = TokenParseUtil.parseToken(authorization);
        // 解析对应的权限以及用户信息
        String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
        LoginUser user = RedisManager.getLoginUser(uuid);
        //查询连接平台类型
        deviceType = deviceType.substring(1, deviceType.length()-1);
        ConnectDeviceTypeEnum typeEnum = ConnectDeviceTypeEnum.getDeviceType(deviceType);
        if(typeEnum == null){
            errorMessage("未能识别客户端类型,请检查deviceType字段" , session);
            return;
        }



        //判断token是否寻找到对应的用户
        if(user != null){
                this.userId = user.getUserId();
                this.userName = user.getUsername();
                this.session = session;
                this.type = typeEnum.getContent();
                webSocketManager.add(userId, session, user,typeEnum);
//            webSocketManager.addUser(userId,user);
                try {
                    WsResult result = new WsResult.Builder()
                            .code(WsCode.SUCCESS.getCode())
                            .type(WsType.PING.getType())
                            .data("连接成功，当前用户为: " + user.getUsername() + "---当前设备平台为: " + typeEnum.getContent()).build();
                    session.getBasicRemote().sendObject(result);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
        }else{
            //未找到则返回消息并中断连接
            try {
                WsResult result = new WsResult.Builder()
                        .code(WsCode.ERROR.getCode())
                        .type(WsType.PING.getType())
                        .data("未找到对应用户，中断连接").build();
                session.getBasicRemote().sendObject(result);
                session.close();
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        // 在这里处理WebSocket连接中的错误
        log.error("WebSocket发生错误, Throwable = " + throwable.getMessage() + ", UserName = " + this.userName);
        webSocketManager.remove(this.userId,session);
        log.debug("已经成功移除一条错误连接: UserName = " + this.userName);
    }

    @OnClose
    public void onClose(){
        if (session != null) {
            webSocketManager.remove(this.userId, session);
            log.debug("[WebSocket] 退出成功，当前退出用户ID为：" + this.userId + "平台为: " + this.type);
        }
    }

    // ping消息（应答）， 消息确认
    @OnMessage
    public void onMessage(String message) {
        log.debug("[WebSocket] 收到消息：{}",message);
        try {
            WsResult result = new WsResult.Builder()
                    .code(WsCode.SUCCESS.getCode())
                    .type(WsType.PING.getType())
                    .data("已接收到消息:" + message).build();
            session.getBasicRemote().sendObject(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //传递错误信息
    private void errorMessage(String type, Session session){
        try {
            WsResult result = new WsResult.Builder()
                    .code(WsCode.ERROR.getCode())
                    .type(WsType.PING.getType())
                    .data(type).build();
            session.getBasicRemote().sendObject(result);
            session.close();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

}
